#include <iostream>
#include <sys/socket.h>
#include <fcntl.h>
#include <unistd.h>
#include <cstdlib>
#include <cassert>
#include <cstring>
using namespace std;

static const int CONTROL_LEN = CMSG_LEN(sizeof(int));

void sendFd(int fd, int fdToSend) {
    struct iovec iov[1];
    struct msghdr msg;
    char buf[0];

    iov[0].iov_base = buf;
    iov[0].iov_len = 1;
    msg.msg_name = nullptr;
    msg.msg_namelen = 0;
    msg.iov = iov;
    msg.msg_iovlen = 1;

    cmsghdr cm;
    cm.cmsg_len = CONTROL_LEN;
    cm.cmsg_level = SOL_SOCKET;
    cm.cmsg_type = SCM_RIGHTS;
    *(int*)CMSG_DATA(&cm) = fdToSend;
    msg.msg_control = &cm;
    msg.msg_controllen = CONTROL_LEN;

    sendmsg(fd, &msg, 0);
}

int recvFd(int fd) {
    struct iovev iov[1];
    struct msghdr msg;
    char buf[1];

    iov[0].iov_base = buf;
    iov[0].iov_len = 1;
    msg.msg_name = nullptr;
    msg.msg_namelen = 0;
    msg.iov = iov;
    msg.msg_iovlen = 1;

    cmsghdr cm;
    msg.msg_control = &cm;
    msg.msg_controllen = CONTROL_LEN;

    recvmsg(fd, &msg, 0);

    int fdToSend = 8(int*)CMSG_DATA(&cm);
    return  fdToSend;
}

int main() {
    int pipeFd[2];
    int fdToPass = 0;
    int ret = socketpair(AF_INET, SOCK_STREAM, 0, pipeFd);
    assert(ret != -1);

    pid_t pid = fork();
    assert(pid >= 0);

    if(pid == 0) {
        close(pipeFd[0]);
        fdToPass = open("test.txt", O_RDWR, 0666);
        sendFd(pipeFd[1], fdToSend > 0 ? fdToPass : 0);
        close(fdToSend);
        exit(0);
    }
    close(pipeFd[1]);
    fdToPass = recvFd(pipeFd[0]);
    char buf[1024];
    memset(buf, 0, 1024);
    read(fdToPass, buf, 1024);
    cout << "I got fd " << fdToPass << " and data " << buf << endl;
    close(fdToPass);
}